package com.duobaoyu.dby.supply.job.task.supply;

import com.duobaoyu.dby.channel.adapter.bean.message.refund.AfterSaleStatusMessage;
import com.duobaoyu.dby.channel.adapter.bean.refund.AfterSaleItemInfo;
import com.duobaoyu.dby.channel.adapter.bean.refund.AfterSaleOrderInfo;
import com.duobaoyu.dby.channel.adapter.enums.biz.refund.AfterSaleStatusEnum;
import com.duobaoyu.dby.channel.boundary.bean.refund.result.AfterSaleParticularResult;
import com.duobaoyu.dby.channel.common.util.SupplyCollectionUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.refund.AfterSaleBoundaryClient;
import com.duobaoyu.dby.supply.biz.client.resource.ResourceApiClient;
import com.duobaoyu.dby.supply.biz.client.resource.bean.bo.OrderRuleConfigBO;
import com.duobaoyu.dby.supply.biz.constant.OperateSourceConstants;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleService;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleStateMachine;
import com.duobaoyu.dby.supply.biz.strategy.message.refund.AbstractChannelAfterSaleStateChangeHandler;
import com.duobaoyu.dby.supply.biz.strategy.message.refund.AfterSaleStateChangeMessageAsyncHandler;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleOutBO;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleStateContext;
import com.duobaoyu.dby.supply.common.biz.dto.refund.AfterSaleBatchQuery;
import com.duobaoyu.dby.supply.core.framework.util.FrameworkUtils;
import com.google.common.collect.Lists;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author yw
 * @description
 * @date 2023/10/11 15:22
 */
@Component
@RequiredArgsConstructor
public class SupplyChainAfterSalesTask {
    private final ResourceApiClient resourceApiClient;
    private final AfterSaleService afterSaleService;
    private final AfterSaleStateMachine afterSaleStateMachine;
	private final AfterSaleBoundaryClient afterSaleBoundaryClient;

    /**
     * 针对于部分渠道一直停留在带用户确认,自动流转到完成
     */
    @XxlJob("refundSystemConfirmCompletedJobHandler")
    public void refundSystemConfirmCompletedTask() {
        afterSaleAutoComplete();

        afterSaleAutoCancel();
    }

    private void afterSaleAutoCancel() {
        int state = AfterSaleStatusEnum.TO_BE_SENT_BACK_BY_BUYER.getValue();

        AfterSaleBatchQuery query = AfterSaleBatchQuery.builder()
                .statusList(Lists.newArrayList(state))
                .build();

		List<AfterSaleOutBO> cancelList = afterSaleService.batchQueryAfterSale(query);
		Map<String, OrderRuleConfigBO> orderRuleConfigMap = queryRuleConfig(cancelList);

		List<AfterSaleOutBO> needChangeInfoList = cancelList.stream()
				.filter(item -> checkNeedToAutoChangeState(item, orderRuleConfigMap.get(item.getChannelCode()),
						(OrderRuleConfigBO orderRuleConfig) -> Objects.nonNull(orderRuleConfig.getOrderRule().getReturnProductRefundCancelTime()) &&
								item.getUpdateTime().plusDays(orderRuleConfig.getOrderRule().getReturnProductRefundCancelTime())
										.isBefore(LocalDateTime.now())))
				.collect(Collectors.toList());

		for (AfterSaleOutBO afterSale : needChangeInfoList) {
			AfterSaleStateContext context = new AfterSaleStateContext();
			context.setAfterSale(afterSale);
			context.setOperateSource(OperateSourceConstants.JOB);
			context.setChangeContentOperate(AfterSaleStateContext.ChangeContentOperate.builder().cancelRemark("系统自动取消").build());
			context.setCurrentAfterSaleStatus(AfterSaleStatusEnum.CLOSE.getValue());
			afterSaleStateMachine.exe(context);
		}
    }

    private void afterSaleAutoComplete() {
        int state = AfterSaleStatusEnum.TO_BE_CONFIRMED_BY_USER.getValue();
        AfterSaleBatchQuery query = AfterSaleBatchQuery.builder()
                .statusList(Lists.newArrayList(state))
                .build();

		List<AfterSaleOutBO> autoCompleteList = afterSaleService.batchQueryAfterSale(query);
		Map<String, OrderRuleConfigBO> orderRuleConfigMap = queryRuleConfig(autoCompleteList);

		List<AfterSaleOutBO> needChangeInfoList = autoCompleteList.stream()
				.filter(item -> checkNeedToAutoChangeState(item, orderRuleConfigMap.get(item.getChannelCode()),
						(OrderRuleConfigBO orderRuleConfig) -> Objects.nonNull(orderRuleConfig.getOrderRule().getAutoAfteSaleCompleteTime()) && item.getUpdateTime()
								.plusDays(orderRuleConfig.getOrderRule().getAutoAfteSaleCompleteTime())
								.isBefore(LocalDateTime.now())))
				.collect(Collectors.toList());

		for (AfterSaleOutBO afterSale : needChangeInfoList) {
			AfterSaleStateContext context = new AfterSaleStateContext();
			context.setAfterSale(afterSale);
			context.setOperateSource(OperateSourceConstants.JOB);
			context.setCurrentAfterSaleStatus(AfterSaleStatusEnum.COMPLETED.getValue());
			afterSaleStateMachine.exe(context);
		}
    }

    private Map<String, OrderRuleConfigBO> queryRuleConfig(List<AfterSaleOutBO> afterSaleList) {
        List<String> channelCodeList = afterSaleList.stream()
                .map(AfterSaleOutBO::getChannelCode).distinct().collect(Collectors.toList());

        List<OrderRuleConfigBO> orderRuleConfigList = Lists.newArrayList();
        for (String channelCode : channelCodeList) {
			OrderRuleConfigBO orderRuleConfig = resourceApiClient.queryOrderRuleConfig(channelCode);
			if (ObjectUtils.isNotEmpty(orderRuleConfig)) {
				orderRuleConfigList.add(orderRuleConfig);
			}
        }
        return orderRuleConfigList.stream()
                .collect(Collectors.toMap(OrderRuleConfigBO::getChannelCode, Function.identity(), (k1, k2) -> k1));

    }

    private boolean checkNeedToAutoChangeState(AfterSaleOutBO item,
                                               OrderRuleConfigBO orderRuleConfig,
                                               Predicate<OrderRuleConfigBO> predicate) {
        if (Objects.isNull(item)
                || Objects.isNull(orderRuleConfig)
                || Objects.isNull(orderRuleConfig.getOrderRule())) {
            return false;
        }
        return predicate.test(orderRuleConfig);
    }

	@XxlJob("afterSaleStatusSyncHandler")
	public void syncAfterSaleStatus() {
		List<Integer> stateList = Lists.newArrayList(AfterSaleStatusEnum.TO_BE_REVIEWED_BY_CHANNEL.getValue(),
				AfterSaleStatusEnum.CHANNEL_AUDIT_SUCCESS.getValue(),
				AfterSaleStatusEnum.TO_BE_SENT_BACK_BY_BUYER.getValue(),
				AfterSaleStatusEnum.PENDING_RECEIPT.getValue());

		AfterSaleBatchQuery query = AfterSaleBatchQuery.builder()
				.statusList(stateList)
				.build();
		List<AfterSaleOutBO> waitSyncList = afterSaleService.batchQueryAfterSale(query); //上限100
		for (AfterSaleOutBO afterSale : waitSyncList) {
			AfterSaleParticularResult afterSaleParticularResult = afterSaleBoundaryClient.queryAfterSale(afterSale);
			List<AfterSaleItemInfo> afterSaleItemInfoList = afterSaleParticularResult.getAfterSaleItemInfoList();
			Integer status = SupplyCollectionUtils.getSingleData(afterSaleItemInfoList).getAfterSaleStatus();
			if (afterSale.getStatus().equals(status)) {
				continue;
			}
			AfterSaleOrderInfo afterSaleOrderInfo = afterSaleParticularResult.getAfterSaleOrderInfo();
			AfterSaleStatusMessage statusMessage = new AfterSaleStatusMessage();
			statusMessage.setAfterSaleStatus(status);
			statusMessage.setFailReason(afterSaleOrderInfo.getRejectReason());
			AfterSaleStatusMessage.RefundInfo refundInfo = new AfterSaleStatusMessage.RefundInfo();
			refundInfo.setRefundAmount(afterSaleOrderInfo.getChannelRealRefundAmount());
			statusMessage.setRefundInfo(refundInfo);
			statusMessage.setChannelAfterSaleSn(afterSaleParticularResult.getChannelAfterSaleSn());
			AfterSaleStateChangeMessageAsyncHandler.Context context =
					new AfterSaleStateChangeMessageAsyncHandler.Context(Lists.newArrayList(statusMessage), Lists.newArrayList(afterSale));
			FrameworkUtils.strategyInstance(AbstractChannelAfterSaleStateChangeHandler.class)
					.strategyHandler(context);
		}
	}
}
